#include <stdio.h>
#include "common.h"
#include <time.h>
#include <math.h>

float steps_to_mm(int pos_steps,int subdiv,float lead,float thetaPerStep)
{
    float totalTheta = pos_steps/subdiv*thetaPerStep;

    float pos_mm = totalTheta/360* lead;

    return pos_mm;
}

int mm_to_steps(float pos_mm,int subdiv,float lead,float thetaPerStep)
{
    float totalTheta = pos_mm/lead * 360;

    float pos_steps = totalTheta*subdiv/thetaPerStep;  

    return (int)pos_steps; 
}


void getCurrTime(char * timeStrOut)
{
    time_t t;
	struct tm *timeinfo; 
    struct tm timeinfoOut;

    if(timeStrOut==NULL)
    {
        return;
    }
	time(&t);
	timeinfo = gmtime_r(&t,&timeinfoOut);

    asctime_r(&timeinfoOut,timeStrOut);
	//printf("ʱ�䣺%s\n", asctime_r(&timeinfoOut,timeStrOut));  //���ַ�����ʽ���localtime����ʱ��

}



//return 0, means ok, else the result is invalid
int volumeToHeight(int volumeIn, int bottomTypeIn, float* heightOut)
{   
    const int VOLUME_SEMISPHERE = 134;//ul
    const float VOLUME_CONE = 25.54;//pi*r*r*r/3 r=2.9
    if(volumeIn < 0)
    {
        return 1;
    }
    else if(volumeIn<VOLUME_SEMISPHERE && 
    (bottomTypeIn == TUBE_BOTTOM_SEMISPHERE
    ||TUBE_CUBE_DP8_REAGENT == bottomTypeIn)
    )
    {
        *heightOut = 2;
        return 0;
    }
    else if(volumeIn<VOLUME_CONE && bottomTypeIn == TUBE_BOTTOM_CONE)
    {
        *heightOut = 2;
        return 0;
    }



    if(bottomTypeIn == TUBE_BOTTOM_SEMISPHERE || TUBE_CUBE_DP8_REAGENT == bottomTypeIn)
    {
        //cross area = 
        float area_cross = 50.265482;//88.24733764; //mm square r = 4mm
        if(TUBE_CUBE_DP8_REAGENT == bottomTypeIn)
        {
           area_cross =  64;//side length is 8
        }
        *heightOut = (float)(volumeIn - VOLUME_SEMISPHERE)/area_cross + 4;
    }
    else if(bottomTypeIn == TUBE_BOTTOM_CONE)
    {
        //const float coeff = 16.755161; //pi * r* r / 3, r = 2.9
        float area_cross = 26.421;//pi * r * r r=2.9
        *heightOut = (float)(volumeIn - VOLUME_CONE)/area_cross + 4;
    }

    return 0;
}

float calcHeight_cylinder(const float rIn, const float pi_r2, const int volumeIn);
float calcHeight_cy_semi(const float rIn, const float pi_r2, const int volumeIn,float bottomVolumeIn);
float calcHeight_cy_cone(const float sqValue, const float pi_r2,const int volumeIn,const float bottomHeightIn,float bottomVolumeIn,float cotValue);
float calcHeight_pcr_48holes(const float pi_r2In,const int volumeIn,const float bottomHeightIn,float bottomVolumeIn);

float calcHeight_pu_reagent1(const float pi_r2In,const int volumeIn,const float bottomHeightIn,float bottomVolumeIn);

typedef enum
{
    SHAPE_CYLINDER,
    SHAPE_CY_SEMI,
    SHAPE_CY_CONE,
}en_container_shape;

int volumeToHeight_en(int volumeIn, int containerTypeIn, float* heightOut)
{
    int ret = 1;
    int containerShape = SHAPE_CYLINDER;
    float radius = 0;
    float bottomHeight = 0;
    float bottomVolume = 0;
    float cotValue = 0;
    float pi_r2 = 0;
    float sqValue = 0;
    switch (containerTypeIn)
    {
        case CONTAINER_PCR_BOARD:
        {
            radius = 2.9;
            cotValue = 4.927;//12.49/2.9
            bottomHeight = 12.49;
            bottomVolume = 109.999;
            pi_r2 = 26.42;
            sqValue = 0.1938;//3/pi/cot
            containerShape = SHAPE_CY_CONE;
            ret = 0;
        }
        break; 
        case CONTAINER_PCR_REAGENT:
        {
            radius = 4.55;
            cotValue = 0.879;//4/4.55
            bottomHeight = 4;
            bottomVolume = 86.718; 
            pi_r2 = 65.039;
            sqValue = 1.0864;//3/pi/cot
            containerShape = SHAPE_CY_CONE;
            ret = 0;
        }
        break;
        case CONTAINER_PU_REAGENT1:
        {
            radius = 5.15;
            cotValue = 5.3146;//27.37/5.15
            bottomHeight = 27.37;
            bottomVolume = 1000;
            sqValue = 0.1797;//3/pi/cot
            containerShape = SHAPE_CY_CONE;
            pi_r2 = 83.323;
            ret = 0;
        }
        break;
        case CONTAINER_PU_SPLIT:
        {
            radius = 16.2;
            pi_r2 = 824.4796;
            containerShape = SHAPE_CYLINDER;
            ret = 0;
        }
        break; 
        case CONTAINER_8TUBE:
        {
            radius = 3.95;
            bottomHeight = 3.95;
            bottomVolume = 129.077;
            pi_r2 = 49.0167;
            containerShape = SHAPE_CY_SEMI;
            ret = 0;
        }
        break; 
        case CONTAINER_TUBE_SAMPLE:
        {
            radius = 5.225;
            bottomHeight = 5.225;
            bottomVolume = 298.7566;
            pi_r2 = 16.415;
            containerShape = SHAPE_CY_SEMI;
            ret = 0;
        }
        break; 
        case CONTAINER_PU_REAGENT2:
        {
            radius = 4.025;
            bottomHeight = 4.025;
            bottomVolume = 136.57;
            pi_r2 = 50.896;
            containerShape = SHAPE_CY_SEMI;
            ret = 0;
        }
        break;       
        default:
        {
          ret = 1;
        }
        break;
    }

    if(ret)
    {
        return ret;
    }

    if(SHAPE_CYLINDER==containerShape)
    {
        * heightOut = calcHeight_cylinder(radius, pi_r2, volumeIn);
    }
    else if(SHAPE_CY_SEMI == containerShape)
    {
        * heightOut = calcHeight_cy_semi(radius, pi_r2, volumeIn,bottomVolume);
    }
    else if(SHAPE_CY_CONE == containerShape)
    {
        if(containerTypeIn == CONTAINER_PCR_REAGENT)
        {
            * heightOut = calcHeight_cy_cone(sqValue, pi_r2, volumeIn,bottomHeight, bottomVolume,cotValue);            
        }
        else if(containerTypeIn == CONTAINER_PCR_BOARD)
        {
            * heightOut = calcHeight_pcr_48holes(pi_r2,volumeIn,bottomHeight,bottomVolume);
        }
        else if(containerTypeIn == CONTAINER_PU_REAGENT1)
        {
            * heightOut = calcHeight_pu_reagent1(pi_r2,volumeIn,bottomHeight,bottomVolume);
        }
        
    }
    else
    {
        ret = 2;
    }

    return ret;    
}


float calcHeight_cylinder(const float rIn,const float pi_r2In, const int volumeIn)
{
    float heightResult = 0;
    heightResult = volumeIn/pi_r2In;
    return heightResult;
}
float calcHeight_cy_semi(const float rIn,const float pi_r2In, const int volumeIn,float bottomVolumeIn)
{
    float heightResult = 0;

    if(bottomVolumeIn > volumeIn)
    {
        heightResult = 1.5;
    }
    else
    {
        heightResult = (volumeIn-bottomVolumeIn)/pi_r2In + rIn;
    }
    
    heightResult -= 2;

    if(heightResult < 1.5)
    {
        heightResult = 1.5;
    }

    return heightResult;    
}
float calcHeight_cy_cone(const float sqValue, const float pi_r2In,const int volumeIn,const float bottomHeightIn,float bottomVolumeIn,float cotValue)
{
    float heightResult = 0;

    if(volumeIn < bottomVolumeIn)
    {
        heightResult = powf(sqValue*volumeIn,0.33333)*cotValue;
    }
    else
    {
        heightResult =  bottomHeightIn + (volumeIn-bottomVolumeIn)/pi_r2In;      
    }

    //heightResult -= 2;

    if(heightResult < 1.5)
    {
        heightResult = 1.5;
    }
    
    return heightResult;     
}

int max_num_vh_arr[3] = {10,20,20};

const volume_height vhParam_48holes[10] = 
{
    {
        .volume = 10,
        .height = 2.394,
    },
    {
        .volume = 20,
        .height = 3.811,
    },
    {
        .volume = 30,
        .height = 4.928,
    },
    {
        .volume = 40,
        .height = 5.867,
    },
    {
        .volume = 50,
        .height = 6.686,
    },
    {
        .volume = 60,
        .height = 7.416,
    },
    {
        .volume = 70,
        .height = 8.078,
    },
    {
        .volume = 80,
        .height = 8.687,
    },
    {
        .volume = 90,
        .height = 9.251,
    },
    {
        .volume = 100,
        .height = 9.779,
    }        

};

// const volume_height vhParam_pcr_reagent[20] = 
// {
//     //{},
//     //{},
// };

const volume_height vhParam_pu_reagent[20] = {
    {
        .volume = 50,
        .height = 5.646,
    },
    {
        .volume = 100,
        .height = 8.626,
    },
    {
        .volume = 150,
        .height = 10.85,
    },
    {
        .volume = 200,
        .height = 12.667,
    },
    {
        .volume = 250,
        .height = 14.225,
    },
    {
        .volume = 300,
        .height = 15.60,
    },
    {
        .volume = 350,
        .height = 16.838,
    },
    {
        .volume = 400,
        .height = 17.969,
    },
    {
        .volume = 450,
        .height = 19.012,
    },
    {
        .volume = 500,
        .height = 19.984,
    },
        {
        .volume = 550,
        .height = 20.896,
    },
    {
        .volume = 600,
        .height = 21.755,
    },
    {
        .volume = 650,
        .height = 22.57,
    },
    {
        .volume = 700,
        .height = 23.344,
    },
    {
        .volume = 750,
        .height = 24.084,
    },
    {
        .volume = 800,
        .height = 24.792,
    },
    {
        .volume = 850,
        .height = 25.472,
    },
    {
        .volume = 900,
        .height = 26.126,
    },
    {
        .volume = 950,
        .height = 26.756,
    },
    {
        .volume = 1000,
        .height = 27.366,
    }
};

float calcHeight_pcr_48holes(const float pi_r2In,const int volumeIn,const float bottomHeightIn,float bottomVolumeIn)
{
    float heightResult = 0;

    if(volumeIn < bottomVolumeIn)
    {
        int index = (int)(volumeIn/10);

        if(index >=0 && index < max_num_vh_arr[CONTAINER_PCR_BOARD])
        {
            heightResult = vhParam_48holes[index].height;

            float deltaHeight = vhParam_48holes[index+1].height - vhParam_48holes[index].height;
            float deltaVolume = vhParam_48holes[index+1].volume - vhParam_48holes[index].volume;

            float volumeLess = volumeIn - vhParam_48holes[index].volume;
            if(volumeLess < 0)
            {
                volumeLess = 0 - volumeLess;
            }
            heightResult += volumeLess*deltaHeight/deltaVolume;
        }
        else
        {
            heightResult = bottomHeightIn;
        }
                
    }
    else
    {
        heightResult =  bottomHeightIn + (volumeIn-bottomVolumeIn)/pi_r2In;      
    }

    heightResult -= 2;

    if(heightResult < 1.5)
    {
        heightResult = 1.5;
    }
    
    return heightResult;     
}

float calcHeight_pu_reagent1(const float pi_r2In,const int volumeIn,const float bottomHeightIn,float bottomVolumeIn)
{
    float heightResult = 0;

    if(volumeIn < bottomVolumeIn)
    {
        int index = (int)(volumeIn / 50);

        printf("in calcHeight_pu_reagent1, index = %d\n",index);

        if(index >= 0 && index < 20)
        {
            printf("height:%f,volume:%f\n",vhParam_pu_reagent[index].height,vhParam_pu_reagent[index].volume);
            heightResult = vhParam_pu_reagent[index].height;

            if(index < 19)
            {
                float deltaHeight = vhParam_pu_reagent[index+1].height - vhParam_pu_reagent[index].height;
                float deltaVolume = vhParam_pu_reagent[index+1].volume - vhParam_pu_reagent[index].volume;

                float volumeLess = volumeIn - vhParam_pu_reagent[index].volume;
                if(volumeLess < 0)
                {
                    volumeLess = 0 - volumeLess;
                }
                heightResult += volumeLess*deltaHeight/deltaVolume;
            }
        }
        else
        {
            heightResult = 1.5;
        }
    }
    else
    {
        heightResult =  bottomHeightIn + (volumeIn-bottomVolumeIn)/pi_r2In; 
        printf("upon cone, heightresult:%f\n",heightResult);     
    }

    heightResult -= 2;

    if(heightResult < 1.5)
    {
        heightResult = 1.5;
    }
    
    return heightResult;     
}

